//
//  BEArrayExtension.swift
//  BasicExtentions
//
//  Created by Fanxx on 2020/7/10.
//

import UIKit

extension Array {
    public init(nonNil elements: Element?...) {
        self = elements.compactMap { $0 }
    }
    ///若没有返回nil，可用负数从后往前取，获取正确的索引
    private func index(for location: Int) -> Int? {
        var i = location
        if location < 0 {
            i = self.count + location
        }
        if i >= 0 && i < self.count {
            return i
        }
        return nil
    }
    /// 检查数组边界，可用负数从后往前取
    public subscript(bounded location: Int) -> Element? {
        get {
            return self.index(for: location).map { self[$0] }
        }
        set {
            self.index(for: location) ??> {
                if let newValue {
                    self[$0] = newValue
                } else {
                    self.remove(at: $0)
                }
            }
        }
    }
    ///将多个数组组合成一个
    public static func union<S>(_ contents: [S?]) -> Self where Self.Element == S.Element, S:Sequence {
        var result = Self()
        for content in contents {
            if let c = content {
                result.append(contentsOf: c)
            }
        }
        return result
    }
    ///将多个数组组合成一个
    public static func union<S>(_ contents: S?...) -> Self where Self.Element == S.Element, S:Sequence {
        return self.union(contents)
    }
    ///将多个数组组合成一个
    @discardableResult
    public mutating func union<S>(_ contents: S?...) -> Self where Self.Element == S.Element, S:Sequence {
        for content in contents {
            if let c = content {
                self.append(contentsOf: c)
            }
        }
        return self
    }
    ///去重，只保留相同元素的第一个
    @discardableResult
    public mutating func distinctFirst(where predicate: (Element, Element) -> Bool) -> Self {
        if self.count > 1 {
            var i = 0
            while i < self.count - 1 {
                var j = i + 1
                while j < self.count {
                    //两个元素相同直接删掉后面那个,这样再后面的索引会往前移，所以J不用+1
                    if predicate(self[i], self[j]) {
                        self.remove(at: j)
                    }else {
                        j += 1
                    }
                }
                //因为i只和后面的比，不会出现前面或当前被删的情况，所以i固定+1
                i += 1
            }
        }
        return self
    }
    ///去重，只保留相同元素的最后一个
    @discardableResult
    public mutating func distinctLast(where predicate: (Element, Element) -> Bool) -> Self {
        if self.count > 1 {
            var i = self.count - 1
            while i > 0 {
                var j = i - 1
                while j >= 0 {
                    //两个元素相同直接删掉前面那个,因为i在后面，所以i元素索引会往前移,要减1才会定位回原元素
                    if predicate(self[i], self[j]) {
                        self.remove(at: j)
                        i -= 1
                    }
                    //因为删的元素是当前位置，不会导致前面的元素变更索引，所以不管有没删都要减1
                    j -= 1
                }
                i -= 1
            }
        }
        return self
    }
    ///去重，只保留相同元素的第一个
    public func byDistinctFirst(where predicate: (Element, Element) -> Bool) -> Self {
        var temp = self
        return temp.distinctFirst(where: predicate)
    }
    ///去重，只保留相同元素的最后一个
    public func byDistinctLast(where predicate: (Element, Element) -> Bool) -> Self {
        var temp = self
        return temp.distinctLast(where: predicate)
    }
    ///循环索引
    public func forEachIndex(_ action:(Int,Element) -> Void) {
        var i = 0
        self.forEach { element in
            action(i, element)
            i += 1
        }
    }
    ///反向循环索引
    public func forEachReversedIndex(_ action:(Int,Element) -> Void) {
        var i = self.count - 1
        self.reversed().forEach { element in
            action(i, element)
            i -= 1
        }
    }
    ///将相邻两个元素拿去做计算，若要汇总信息使用系统提供的reduce方法
    public func forEachNeighbor(_ action:(Element,Element) -> Void) {
        if self.count > 1 {
            for i in 1..<self.count {
                action(self[i - 1], self[i])
            }
        }
    }
    /// 随机取几个值
    public func random(_ count: Int = 1) -> Self {
        guard self.count > count else { return self }
        // 超过一半数量，使用减法
        if self.count / 2 < count {
            var result = self
            while result.count > count {
                let index = Int.random(in: 0..<result.count)
                result.remove(at: index)
            }
            return result
        }else{
            // 低于一半数量使用加法
            var result: Self = []
            var resultIndexs: [Int] = []
            while result.count < count {
                let index = Int.random(in: 0..<self.count)
                if !resultIndexs.contains(index) {
                    result.append(self[index])
                    resultIndexs.append(index)
                }
            }
            return result
        }
    }
    /// 随机取个值
    public var random: Element? {
        guard self.count > 0 else { return nil }
        let index = Int.random(in: 0..<self.count)
        return self[index]
    }
    /// 删除并返回第一个元素
    public mutating func popFirst() -> Element? {
        guard self.count > 0 else { return nil }
        return self.removeFirst()
    }
    /// 分组
    public func group<CompareValue: Comparable>(by comparator: (Element) -> CompareValue) -> [CompareValue: Self] {
        var result: [CompareValue: Self] = [:]
        self.forEach { element in
            let key = comparator(element)
            result[key] ?+= element
        }
        return result
    }
    /// 分组
    public func group<CompareValue: Comparable>(by keyPath: KeyPath<Element, CompareValue>) -> [CompareValue: Self] {
        return self.group { $0[keyPath: keyPath] }
    }
    /// 取第一个非空的转换
    public func firstCompactMap<ElementOfResult>(transform: (Element) throws -> ElementOfResult?) rethrows -> ElementOfResult? {
        for e in self {
            if let result = try transform(e) {
                return result
            }
        }
        return nil
    }
    /// 排序
    @inlinable public mutating func sort<CompareValue: Comparable>(by areInIncreasingOrder: (CompareValue, CompareValue) throws -> Bool, for keyPath: KeyPath<Element, CompareValue>) rethrows {
        try self.sort(by: { try areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) })
    }
    /// 排序
    @inlinable public func sorted<CompareValue: Comparable>(by areInIncreasingOrder: (CompareValue, CompareValue) throws -> Bool, for keyPath: KeyPath<Element, CompareValue>) rethrows -> [Element] {
        return try self.sorted(by: { try areInIncreasingOrder($0[keyPath: keyPath], $1[keyPath: keyPath]) })
    }
    @inlinable public func map<T>(_ keyPath: KeyPath<Element, T>) -> [T] {
        return self.map { $0[keyPath: keyPath] }
    }
    @inlinable public func compactMap<T>(_ keyPath: KeyPath<Element, T?>) -> [T] {
        return self.compactMap { $0[keyPath: keyPath] }
    }
}

extension Array where Element: Comparable {
    ///去重，只保留相同元素的第一个
    @discardableResult
    public mutating func distinctFirst() -> Self {
        return self.distinctFirst(where: { $0 == $1 })
    }
    ///去重，只保留相同元素的最后一个
    @discardableResult
    public mutating func distinctLast() -> Self {
        return self.distinctLast(where: { $0 == $1 })
    }
    ///去重，只保留相同元素的第一个
    public func byDistinctFirst() -> Self {
        var temp = self
        return temp.distinctFirst()
    }
    ///去重，只保留相同元素的最后一个
    public func byDistinctLast() -> Self {
        var temp = self
        return temp.distinctLast()
    }
}

extension Array where Element: Numeric {
    /// 汇总
    public func sum() -> Element {
        return self.reduce(0, +)
    }
}

extension ArraySlice {
    /// 转换成数组
    public func asArray() -> [Element] {
        return Array(self)
    }
}
